#!coding:utf-8
# vim: tabstop=4 shiftwidth=4 softtabstop=4

from datetime import datetime
from django.db import transaction
from django.db.models import Count
from rest_framework.response import Response
from rest_framework import status

from cvirt.cnode.vm import vm_utils
from cvirt.tasks.network import createNat, createIsolate
from cvirt.tasks.storage import attach
from cvirt.manager.models import Server,Instance, Cluster, Storage, Network
from cvirt.manager.serializers import HostSerializer, VMSerializer
from cvirt.manager.views import BaseListAPIView, BaseRetriveAPIView, NamedAPIViewMixIn
from cvirt.common.ssh import get_connection
from cvirt.common import config
from cvirt.common import constant
from cvirt.fence import fence_drac5
from cvirt.common import translate as _

conf = config.load_settings()
BONDNAME = conf['bond.name']
class HostList(NamedAPIViewMixIn,BaseListAPIView):
    model = Server
    serializer_class = HostSerializer
    def _build_vminfo(self,host):
        vms_info = []
        instances = Instance.objects.filter(host_id=host.id)
        for inst in instances:
            vms_info.append({"id":inst.id,"name":inst.name,"status":inst.status,"os_type":inst.os_type})

        return vms_info

    def status(self,request, *args, **kwargs):
        ids = self.get_query_string('ids')
        if ids:
            hosts = Server.objects.filter(id__in=map(int,ids.split(',')))
        else:
            hosts = Server.objects.all()

        alives = attach.ping(*map(lambda s:s.host_name,hosts))

        def set_status(s):
            if s.status not in [0,1]:
                if not s.host_name in alives:
                    s.update(dict(status=3))
                else:
                    s.update(dict(status=2))
            return s

        if ids:
            return Response([{'cpu_usage':host.cpu_usage,
                           'id':host.id,
                           'mem_usage':host.mem_usage,
                           'status':host.status} for host in map(set_status,hosts)])

        return Response({})

        
class HostInfo(NamedAPIViewMixIn,BaseRetriveAPIView):
    model = Server
    serializer_class = HostSerializer

    def _get(self, request, *args, **kwargs):
        host = Server.objects.get_or_none(pk=self.pk)
        response = self.retrieve(request,*args,**kwargs)
        if host:
            os_types = Instance.objects.values('os_type').filter(host=host).annotate(count=Count('os_type'))
            os_types = dict([(os['os_type'],os['count']) for os in os_types])

            response.data.update(dict(os_info=os_types))

        return response

    def build_updown_bond(self, conn):
        "https://bugs.launchpad.net/ubuntu/+source/ifenslave-2.6/+bug/1073820"
        _, output = conn.execute('cat /etc/network/interfaces')
        eth = None
        bondslaves = []
        for l in output:
            if 'auto' in l:
                eth = l.split()[-1]
            if 'bond-master %s' % BONDNAME in l:
                bondslaves.append(eth)

        bondslaves.append(BONDNAME)
        downcmd = ["ifdown %s" % e for e in bondslaves]
        upcmd = ["ifup %s" % e for e in bondslaves]
        return "%s;%s" % (";".join(downcmd),";".join(upcmd))

    def clear_bond_config(self, conn):
        _, out = conn.execute('cat /etc/network/interfaces')
        bondconfig = []
        hit_bond = False
        for l in out:
            if not hit_bond:
                hit_bond = 'auto %s' % BONDNAME in l
            if hit_bond:
                if l.startswith('address') or l.startswith('netmask') or l.startswith('gateway'):
                    l = ""
            bondconfig.append(l)
        conn.execute("echo '%s' > /etc/network/interfaces" % "".join(bondconfig))

    def _setup_bond(self, conn,address , dns, gateway, netmask, usedhcp):
        #清除上次的配置address,netmask,gateway
        # conn.execute("sed -i 's/^[ang].*#bond0$//g' /etc/network/interfaces" )
        self.clear_bond_config(conn)
        eth_type = "dhcp" if usedhcp else "static"
        conn.execute("sed -i 's/iface %s inet .*/iface %s inet %s/g' /etc/network/interfaces" % (BONDNAME,BONDNAME,eth_type))
        if not usedhcp:
            conn.execute("echo 'address %s' >> /etc/network/interfaces" % address)
            conn.execute("echo 'netmask %s' >> /etc/network/interfaces" % netmask)
            conn.execute("echo 'gateway %s' >> /etc/network/interfaces" % gateway)
        if dns:
            conn.execute("echo 'nameserver %s' >> /etc/resolv.conf" % dns)
        conn.execute(self.build_updown_bond(conn))

    @transaction.autocommit
    def activate(self,request, *args, **kwargs):
        hostparams = self.get_params('host')
        cluster_id = hostparams['cluster']['id']
        usedhcp = hostparams['usedhcp']
        address = hostparams['address']
        netmask = hostparams['netmask']
        gateway = hostparams['gateway']
        dns = hostparams['dns1']
        hostname = hostparams['host_name']

        powertool = hostparams['powertool']
        powercard_address = hostparams['powercard_address']
        powercard_username = hostparams['powercard_username']
        powercard_password = hostparams['powercard_password']

        cluster = Cluster.objects.get_or_none(pk=cluster_id)
        host = Server.objects.get_or_none(pk=self.kwargs.get('pk'))
        #如果存在相同的host name,提示用户
        if host.host_name != hostname and Server.objects.filter(host_name=hostname).count()>0:
            return Response(_('主机名%s已存在' % hostname),status.HTTP_400_BAD_REQUEST)

        # expect_status = host.status if self.action == 'update' else 1

        if host and cluster:
            if host.status == 3:
                return Response(_('不能修改已关闭的主机'),status.HTTP_400_BAD_REQUEST)
            #不允许修改cluster
            if self.action == 'update' and cluster.id != host.cluster.id:
                return Response(_("已激活的主机不能修改集群"),status.HTTP_400_BAD_REQUEST)
            try:
                conn = get_connection(host.ip,username='root',password=host.password)
                self._setup_bond(conn,address, dns, gateway, netmask, usedhcp)
                #修改hostname
                if hostname != host.host_name:
                    conn.execute("hostname %s;sed -i 's/%s/%s/g' /etc/hostname /etc/hosts" % (hostname,host.host_name,hostname))

                # expect_action = 'restart' if self.action == 'update' else 'start'
                expect_action = 'restart'
                #保存hostid
                conn.execute("sed -i 's/HOSTID=.*/HOSTID=%s/g' /opt/tcloud/conf.d/cnode.run" % host.id)
                host.update(dict(cluster=cluster,status = 2,usedhcp=usedhcp,address=address,netmask=netmask,gateway=gateway,
                                 dns1=dns,host_name=hostname,powertool=powertool,powercard_address=powercard_address,
                                 powercard_username=powercard_username,powercard_password=powercard_password,memshare=hostparams['memshare']))
                #更新完数据库后，cnode service会执行存储和网络的初始化
                conn.execute("/etc/init.d/celeryd %s" % expect_action)
            except:
                return Response(_('连接主机失败，请重试!'),status.HTTP_400_BAD_REQUEST)

            return Response(self.get_serializer(host).data, 200)

        return Response(_("集群id或者主机id不能为空"), status=status.HTTP_400_BAD_REQUEST)


    def maintain(self,request, *args, **kwargs):
        pass

    def start(self,request, *args, **kwargs):
        host = Server.objects.get_or_none(pk=self.kwargs.get('pk'))

        remoteCardManager = RemoteCardManager()

        if remoteCardManager.doAction("on", host) != 0:
            return Response(status=status.HTTP_500_INTERNAL_SERVER_ERROR)

        # 将主机的状态置为正常
        host.update(dict(status = 2))

        return Response(status=status.HTTP_200_OK)

    def shutdown(self,request, *args, **kwargs):
        host = Server.objects.get_or_none(pk=self.kwargs.get('pk'))

        remoteCardManager = RemoteCardManager()

        if remoteCardManager.doAction("off", host) != 0:
            return Response(status=status.HTTP_500_INTERNAL_SERVER_ERROR)

        # 将主机的状态置为离线
        host.update(dict(status = 3))

        return Response(status=status.HTTP_200_OK)

    def reboot(self,request, *args, **kwargs):
        host = Server.objects.get_or_none(pk=self.kwargs.get('pk'))

        remoteCardManager = RemoteCardManager()

        if remoteCardManager.doAction("reboot", host) != 0:
            return Response(status=status.HTTP_500_INTERNAL_SERVER_ERROR)

        # 将主机的状态置为正常
        host.update(dict(status = 2))

        return Response(status=status.HTTP_200_OK)

    def update(self,request, *args, **kwargs):
        #修改和激活的动作基本相同
        return self.activate(request,*args,**kwargs)

    def vms(self, request, *args, **kwargs):
        host_id = kwargs.get("pk")
        qset = Instance.objects.filter(host_id=host_id)
        data = self.paginate(request,qset,VMSerializer)
        return Response(data)

    @transaction.autocommit
    def current_traffic(self,req,*args,**kwargs):
        stime,result = self._current_usage(req,'network',*args,**kwargs)
        return Response(dict(line1=[stime,result[0]],line2=[stime,result[1]]))

    @transaction.autocommit
    def current_mem(self,req,*args,**kwargs):
        stime,result = self._current_usage(req,'mem',*args,**kwargs)
        return Response(dict(line1=[stime,result[0]],line2=[stime,result[1]]))

    def _current_usage(self,req,type,*args,**kwargs):
        host = Server.objects.get_or_none(pk=self.pk)
        stime = datetime.strftime(datetime.now(),'%H:%M:%S')
        try:
            if host.status != 2:
                return stime,0 if type=='cpu' else (0,0)
            result = vm_utils.hostinfo(host.ip,type,host.password)
        except:
            return stime,0 if type=='cpu' else (0,0)
        return stime,result

    @transaction.autocommit
    def current_cpu(self,req,*args,**kwargs):
        return Response(dict(line1=self._current_usage(req,'cpu',*args,**kwargs)))

    @transaction.commit_on_success
    def remove(self, request, *args, **kwargs):
        host = Server.objects.get_or_none(pk=self.pk)
        if host and host.instance_set.count() ==0:
            try:
                sshconn = get_connection(host.ip,password=host.password)
                sshconn.execute("/etc/init.d/celeryd stop")
            except:
                #停止celery服务不是必须的，如果失败，我们还是可以删除主机
                pass
            #TODO remove network and storage?
            host.delete()
            return Response(status=200)
        return Response(_('主机不允许删除'),status.HTTP_400_BAD_REQUEST)


class RemoteCardManager:

    #使用远程管理卡对服务器进行操作，actionType的取值分别为：on,off,reboot
    def doAction(self, actionType, host):

        parameter = "--ip=%s --username=%s --password=%s --action=%s --ssh --login-timeout=%d" % \
                (host.powercard_address, host.powercard_username, host.powercard_password, actionType, 10)

        try:
            # dell远程管理卡
            if (host.powertool == 1):
                fence_drac5.main(parameter)
        except:
            return -1

        return 0
